jetcrab\bytecode\expressions/
unary.rs

1use crate::ast::Node;
2use crate::vm::instructions::Instruction;
3use crate::vm::types::ConstantIndex;
4
5pub trait UnaryGenerator {
6    fn generate_unary_expression(&mut self, node: &Node);
7    fn generate_update_expression(&mut self, node: &Node);
8}
9
10pub trait UnaryCore {
11    fn instructions(&mut self) -> &mut Vec<Instruction>;
12    fn visit_node(&mut self, node: &Node);
13}
14
15impl<T> UnaryGenerator for T
16where
17    T: UnaryCore + crate::bytecode::scope::local_vars::ScopeManager,
18{
19    fn generate_unary_expression(&mut self, node: &Node) {
20        if let Node::UnaryExpression(expr) = node {
21            self.visit_node(&expr.argument);
22            match expr.operator.as_str() {
23                "!" => self.instructions().push(Instruction::Not),
24                "-" => {
25                    self.instructions()
26                        .push(Instruction::PushConst(ConstantIndex::new(0)));
27                    self.instructions().push(Instruction::Sub);
28                }
29                "+" => {}
30                "~" => {
31                    self.instructions()
32                        .push(Instruction::PushConst(ConstantIndex::new(0)));
33                    self.instructions().push(Instruction::Sub);
34                    self.instructions().push(Instruction::Inc);
35                }
36                "typeof" => self.instructions().push(Instruction::TypeOf),
37                "void" => {
38                    self.instructions().push(Instruction::Pop);
39                    self.instructions().push(Instruction::PushUndefined);
40                }
41                "delete" => self.instructions().push(Instruction::Delete),
42                _ => {}
43            }
44        }
45    }
46
47    fn generate_update_expression(&mut self, node: &Node) {
48        if let Node::UpdateExpression(expr) = node {
49            // For update expressions on variables, we need to load, modify, and store
50            if let Node::Identifier(name) = &*expr.argument {
51                let local_idx = self.get_or_create_local(name);
52
53                // Load the current value
54                self.instructions().push(Instruction::LoadLocal(local_idx));
55
56                match expr.operator.as_str() {
57                    "++" => {
58                        if expr.prefix {
59                            // ++i: increment, store, and leave incremented value on stack
60                            self.instructions().push(Instruction::Inc);
61                            self.instructions().push(Instruction::Dup);
62                            self.instructions().push(Instruction::StoreLocal(local_idx));
63                        } else {
64                            // i++: duplicate original, increment, store incremented
65                            self.instructions().push(Instruction::Dup);
66                            self.instructions().push(Instruction::Inc);
67                            self.instructions().push(Instruction::StoreLocal(local_idx));
68                        }
69                    }
70                    "--" => {
71                        if expr.prefix {
72                            // --i: decrement, store, and leave decremented value on stack
73                            self.instructions().push(Instruction::Dec);
74                            self.instructions().push(Instruction::Dup);
75                            self.instructions().push(Instruction::StoreLocal(local_idx));
76                        } else {
77                            // i--: duplicate original, decrement, store decremented
78                            self.instructions().push(Instruction::Dup);
79                            self.instructions().push(Instruction::Dec);
80                            self.instructions().push(Instruction::StoreLocal(local_idx));
81                        }
82                    }
83                    _ => {
84                        self.instructions().push(Instruction::Inc);
85                        self.instructions().push(Instruction::StoreLocal(local_idx));
86                    }
87                }
88            } else {
89                // For non-variable expressions, just do the operation
90                self.visit_node(&expr.argument);
91                match expr.operator.as_str() {
92                    "++" => {
93                        if expr.prefix {
94                            self.instructions().push(Instruction::Inc);
95                        } else {
96                            self.instructions().push(Instruction::Dup);
97                            self.instructions().push(Instruction::Inc);
98                        }
99                    }
100                    "--" => {
101                        if expr.prefix {
102                            self.instructions().push(Instruction::Dec);
103                        } else {
104                            self.instructions().push(Instruction::Dup);
105                            self.instructions().push(Instruction::Dec);
106                        }
107                    }
108                    _ => {
109                        self.instructions().push(Instruction::Inc);
110                    }
111                }
112            }
113        }
114    }
115}